Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix [7cddd2845c] - crash with >= INT_MAX operands |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk | main |
Files: | files | file ages | folders |
SHA3-256: |
eb734aab392c0b3102b0d8d5e246e2ef |
User & Date: | apnadkarni 2023-04-29 03:15:11.697 |
Context
2023-04-29
| ||
14:50 | Merge 8.7 check-in: 874005b119 user: jan.nijtmans tags: trunk, main | |
03:15 | Fix [7cddd2845c] - crash with >= INT_MAX operands check-in: eb734aab39 user: apnadkarni tags: trunk, main | |
2023-04-28
| ||
06:43 | Limit memset() to "TCL_UTF_MAX=3' builds. check-in: c72b11eac7 user: pooryorick tags: trunk, main | |
2023-04-27
| ||
13:34 | Merge trunk Closed-Leaf check-in: ff2bdedf2c user: apnadkarni tags: bug-7cddd2845c | |
Changes
Changes to generic/tclBasic.c.
︙ | ︙ | |||
5160 5161 5162 5163 5164 5165 5166 | * for the outer-most script/command. See * Tcl_EvalEx() and TclEvalObjEx() for places * generating arguments for which this is * true. */ { Interp *iPtr = (Interp *) interp; const char *p, *next; | | | | | | 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 | * for the outer-most script/command. See * Tcl_EvalEx() and TclEvalObjEx() for places * generating arguments for which this is * true. */ { Interp *iPtr = (Interp *) interp; const char *p, *next; const int minObjs = 20; Tcl_Obj **objv, **objvSpace; int *expand, *lines, *lineSpace; Tcl_Token *tokenPtr; int expandRequested, code = TCL_OK; Tcl_Size bytesLeft, commandLength; CallFrame *savedVarFramePtr;/* Saves old copy of iPtr->varFramePtr in case * TCL_EVAL_GLOBAL was set. */ int allowExceptions = (iPtr->evalFlags & TCL_ALLOW_EXCEPTIONS); int gotParse = 0; Tcl_Size i, objectsUsed = 0; /* These variables keep track of how much * state has been allocated while evaluating * the script, so that it can be freed * properly if an error occurs. */ Tcl_Parse *parsePtr = (Tcl_Parse *)TclStackAlloc(interp, sizeof(Tcl_Parse)); CmdFrame *eeFramePtr = (CmdFrame *)TclStackAlloc(interp, sizeof(CmdFrame)); Tcl_Obj **stackObjArray = (Tcl_Obj **) |
︙ | ︙ | |||
5308 5309 5310 5311 5312 5313 5314 | * continuation line locations to not lose our position for the * per-command parsing. */ Tcl_Size wordLine = line; const char *wordStart = parsePtr->commandStart; int *wordCLNext = clNext; | | | > > | 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 | * continuation line locations to not lose our position for the * per-command parsing. */ Tcl_Size wordLine = line; const char *wordStart = parsePtr->commandStart; int *wordCLNext = clNext; Tcl_Size objectsNeeded = 0; Tcl_Size numWords = parsePtr->numWords; /* * Generate an array of objects for the words of the command. */ if (numWords > minObjs) { expand = (int *)Tcl_Alloc(numWords * sizeof(int)); objvSpace = (Tcl_Obj **)Tcl_Alloc(numWords * sizeof(Tcl_Obj *)); lineSpace = (int *)Tcl_Alloc(numWords * sizeof(int)); } expandRequested = 0; objv = objvSpace; lines = lineSpace; iPtr->cmdFramePtr = eeFramePtr->nextPtr; for (objectsUsed = 0, tokenPtr = parsePtr->tokenPtr; objectsUsed < numWords; objectsUsed++, tokenPtr += tokenPtr->numComponents+1) { Tcl_Size additionalObjsCount; /* * TIP #280. Track lines to current word. Save the information * on a per-word basis, signaling dynamic words as needed. * Make the information available to the recursively called * evaluator as well, including the type of context (source * vs. eval). */ |
︙ | ︙ | |||
5377 5378 5379 5380 5381 5382 5383 | "\n (expanding word %" TCL_Z_MODIFIER "u)", objectsUsed)); Tcl_DecrRefCount(objv[objectsUsed]); break; } expandRequested = 1; expand[objectsUsed] = 1; | | > > > > > > | > > > > | 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 | "\n (expanding word %" TCL_Z_MODIFIER "u)", objectsUsed)); Tcl_DecrRefCount(objv[objectsUsed]); break; } expandRequested = 1; expand[objectsUsed] = 1; additionalObjsCount = (numElements ? numElements : 1); } else { expand[objectsUsed] = 0; additionalObjsCount = 1; } /* Currently max command words in INT_MAX */ if (additionalObjsCount > INT_MAX || objectsNeeded > (INT_MAX - additionalObjsCount)) { code = TclCommandWordLimitError(interp, -1); Tcl_DecrRefCount(objv[objectsUsed]); break; } objectsNeeded += additionalObjsCount; if (wordCLNext) { TclContinuationsEnterDerived(objv[objectsUsed], wordStart - outerScript, wordCLNext); } } /* for loop */ iPtr->cmdFramePtr = eeFramePtr; |
︙ | ︙ |
Changes to generic/tclExecute.c.
︙ | ︙ | |||
977 978 979 980 981 982 983 | * stack to enlarge. */ size_t growth1, /* How much larger than the current used * size. */ int move) /* 1 if move words since last marker. */ { ExecStack *esPtr = eePtr->execStackPtr, *oldPtr = NULL; size_t newBytes; | | | | | 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 | * stack to enlarge. */ size_t growth1, /* How much larger than the current used * size. */ int move) /* 1 if move words since last marker. */ { ExecStack *esPtr = eePtr->execStackPtr, *oldPtr = NULL; size_t newBytes; Tcl_Size growth = growth1; Tcl_Size newElems, currElems, needed = growth - (esPtr->endPtr - esPtr->tosPtr); Tcl_Obj **markerPtr = esPtr->markerPtr, **memStart; Tcl_Size moveWords = 0; if (move) { if (!markerPtr) { Tcl_Panic("STACK: Reallocating with no previous alloc"); } if (needed <= 0) { return MEMSTART(markerPtr); |
︙ | ︙ | |||
2821 2822 2823 2824 2825 2826 2827 | ArgumentBCEnter(interp, codePtr, TD, pc, objc, objv); } DECACHE_STACK_INFO(); pc += pcAdjustment; TEBC_YIELD(); | > > > | > | 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 | ArgumentBCEnter(interp, codePtr, TD, pc, objc, objv); } DECACHE_STACK_INFO(); pc += pcAdjustment; TEBC_YIELD(); if (objc > INT_MAX) { return TclCommandWordLimitError(interp, objc); } else { return TclNREvalObjv(interp, objc, objv, TCL_EVAL_NOERR | TCL_EVAL_SOURCE_IN_FRAME, NULL); } case INST_INVOKE_REPLACE: objc = TclGetUInt4AtPtr(pc+1); opnd = TclGetUInt1AtPtr(pc+5); objPtr = POP_OBJECT(); objv = &OBJ_AT_DEPTH(objc-1); cleanup = objc; |
︙ | ︙ |
Changes to generic/tclInt.h.
︙ | ︙ | |||
4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 | */ MODULE_SCOPE int TclIndexEncode(Tcl_Interp *interp, Tcl_Obj *objPtr, int before, int after, int *indexPtr); MODULE_SCOPE Tcl_Size TclIndexDecode(int encoded, Tcl_Size endValue); MODULE_SCOPE int TclIndexInvalidError(Tcl_Interp *interp, const char *idxType, Tcl_Size idx); #endif /* TCL_MAJOR_VERSION > 8 */ /* Constants used in index value encoding routines. */ #define TCL_INDEX_END ((Tcl_Size)-2) #define TCL_INDEX_START ((Tcl_Size)0) /* | > > > > > > | 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 | */ MODULE_SCOPE int TclIndexEncode(Tcl_Interp *interp, Tcl_Obj *objPtr, int before, int after, int *indexPtr); MODULE_SCOPE Tcl_Size TclIndexDecode(int encoded, Tcl_Size endValue); MODULE_SCOPE int TclIndexInvalidError(Tcl_Interp *interp, const char *idxType, Tcl_Size idx); /* * Error message utility functions */ MODULE_SCOPE int TclCommandWordLimitError(Tcl_Interp *interp, Tcl_Size count); #endif /* TCL_MAJOR_VERSION > 8 */ /* Constants used in index value encoding routines. */ #define TCL_INDEX_END ((Tcl_Size)-2) #define TCL_INDEX_START ((Tcl_Size)0) /* |
︙ | ︙ |
Changes to generic/tclParse.c.
︙ | ︙ | |||
210 211 212 213 214 215 216 | * the parsed command; any previous * information in the structure is ignored. */ { const char *src; /* Points to current character in the * command. */ char type; /* Result returned by CHAR_TYPE(*src). */ Tcl_Token *tokenPtr; /* Pointer to token being filled in. */ | | | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | * the parsed command; any previous * information in the structure is ignored. */ { const char *src; /* Points to current character in the * command. */ char type; /* Result returned by CHAR_TYPE(*src). */ Tcl_Token *tokenPtr; /* Pointer to token being filled in. */ Tcl_Size wordIndex; /* Index of word token for current word. */ int terminators; /* CHAR_TYPE bits that indicate the end of a * command. */ const char *termPtr; /* Set by Tcl_ParseBraces/QuotedString to * point to char after terminating one. */ Tcl_Size scanned; if (numBytes < 0 && start) { |
︙ | ︙ | |||
323 324 325 326 327 328 329 | if (Tcl_ParseQuotedString(interp, src, numBytes, parsePtr, 1, &termPtr) != TCL_OK) { goto error; } src = termPtr; numBytes = parsePtr->end - src; } else if (*src == '{') { | | | | 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 | if (Tcl_ParseQuotedString(interp, src, numBytes, parsePtr, 1, &termPtr) != TCL_OK) { goto error; } src = termPtr; numBytes = parsePtr->end - src; } else if (*src == '{') { Tcl_Size expIdx = wordIndex + 1; Tcl_Token *expPtr; if (Tcl_ParseBraces(interp, src, numBytes, parsePtr, 1, &termPtr) != TCL_OK) { goto error; } src = termPtr; numBytes = parsePtr->end - src; /* * Check whether the braces contained the word expansion prefix * {*} */ expPtr = &parsePtr->tokenPtr[expIdx]; if ((0 == expandWord) /* Haven't seen prefix already */ && (expIdx + 1 == parsePtr->numTokens) /* Only one token */ && (((1 == expPtr->size) /* Same length as prefix */ && (expPtr->start[0] == '*'))) /* Is the prefix */ && (numBytes > 0) && (0 == ParseWhiteSpace(termPtr, numBytes, &parsePtr->incomplete, &type)) |
︙ | ︙ | |||
376 377 378 379 380 381 382 | /* * Finish filling in the token for the word and check for the special * case of a word consisting of a single range of literal text. */ tokenPtr = &parsePtr->tokenPtr[wordIndex]; tokenPtr->size = src - tokenPtr->start; | | | 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 | /* * Finish filling in the token for the word and check for the special * case of a word consisting of a single range of literal text. */ tokenPtr = &parsePtr->tokenPtr[wordIndex]; tokenPtr->size = src - tokenPtr->start; tokenPtr->numComponents = parsePtr->numTokens - (wordIndex + 1); if (expandWord) { Tcl_Size i; int isLiteral = 1; /* * When a command includes a word that is an expanded literal; for * example, {*}{1 2 3}, the parser performs that expansion |
︙ | ︙ | |||
403 404 405 406 407 408 409 | if (tokenPtr[i].type != TCL_TOKEN_TEXT) { isLiteral = 0; break; } } if (isLiteral) { | > | | 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 | if (tokenPtr[i].type != TCL_TOKEN_TEXT) { isLiteral = 0; break; } } if (isLiteral) { Tcl_Size elemCount = 0; int code = TCL_OK, literal = 1; const char *nextElem, *listEnd, *elemStart; /* * The word to be expanded is a literal, so determine the * boundaries of the literal string to be treated as a list * and expanded. That literal string starts at * tokenPtr[1].start, and includes all bytes up to, but not |
︙ | ︙ | |||
467 468 469 470 471 472 473 | } else { /* * Recalculate the number of Tcl_Tokens needed to store * tokens representing the expanded list. */ const char *listStart; | | | | 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 | } else { /* * Recalculate the number of Tcl_Tokens needed to store * tokens representing the expanded list. */ const char *listStart; Tcl_Size growthNeeded = wordIndex + 2*elemCount - parsePtr->numTokens; parsePtr->numWords += elemCount - 1; if (growthNeeded > 0) { TclGrowParseTokenArray(parsePtr, growthNeeded); tokenPtr = &parsePtr->tokenPtr[wordIndex]; } parsePtr->numTokens = wordIndex + 2*elemCount; |
︙ | ︙ |
Changes to generic/tclUtil.c.
︙ | ︙ | |||
3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 | Tcl_Size idx) /* Invalid index value */ { if (interp) { Tcl_SetObjResult(interp, Tcl_ObjPrintf("Invalid %s value %" TCL_SIZE_MODIFIER "d.", idxType ? idxType : "index", idx)); } return TCL_ERROR; /* Always */ } /* *---------------------------------------------------------------------- * | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 | Tcl_Size idx) /* Invalid index value */ { if (interp) { Tcl_SetObjResult(interp, Tcl_ObjPrintf("Invalid %s value %" TCL_SIZE_MODIFIER "d.", idxType ? idxType : "index", idx)); } return TCL_ERROR; /* Always */ } /* *------------------------------------------------------------------------ * * TclCommandWordLimitErrpr -- * * Generates an error message limit on number of command words exceeded. * * Results: * Always return TCL_ERROR. * * Side effects: * If interp is not-NULL, an error message is stored in it. * *------------------------------------------------------------------------ */ int TclCommandWordLimitError ( Tcl_Interp *interp, /* May be NULL */ Tcl_Size count) /* If <= 0, "unknown" */ { if (interp) { if (count > 0) { Tcl_SetObjResult( interp, Tcl_ObjPrintf("Number of words (%" TCL_SIZE_MODIFIER "d) in command exceeds limit %" TCL_SIZE_MODIFIER "d.", count, (Tcl_Size)INT_MAX)); } else { Tcl_SetObjResult(interp, Tcl_ObjPrintf("Number of words in command exceeds " "limit %" TCL_SIZE_MODIFIER "d.", (Tcl_Size)INT_MAX)); } } return TCL_ERROR; /* Always */ } /* *---------------------------------------------------------------------- * |
︙ | ︙ |
Changes to tests/bigdata.test.
︙ | ︙ | |||
875 876 877 878 879 880 881 | [testlutil equal [lrange $l $insidx-10 $insidx+19] [concat $pat $ins $pat]] } -cleanup { bigClean } # # list and {*} | > | | > | > > > > > | > | > > | 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 | [testlutil equal [lrange $l $insidx-10 $insidx+19] [concat $pat $ins $pat]] } -cleanup { bigClean } # # list and {*} # TODO - compiled and uncompiled behave differently so tested separately test list-bigdata-1.compiled {list {*}} -body { set l [bigList 0x100000000] set l2 [list {*}$l] unset l list [llength $l2] [lindex $l2 0] [lindex $l2 end] } -cleanup { bigClean } -constraints { bigdata } -result {4294967296 0 5} test list-bigdata-1.uncompiled {list {*}} -body { set l [bigList 0x7fffffff] testevalex {set l2 [list {*}$l]} } -cleanup { bigClean } -constraints { bigdata } -result {Number of words in command exceeds limit 2147483647.} -returnCodes error # # llength bigtestRO llength-bigdata-1 {llength} 4294967296 -body { llength $l } -setup { set l [bigList 0x100000000] |
︙ | ︙ |